<html>
<head><meta charset="utf-8"><title>Understanding borrow checking of a program · t-compiler/help · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/index.html">t-compiler/help</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html">Understanding borrow checking of a program</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="231065780"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231065780" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> osa1 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231065780">(Mar 19 2021 at 18:05)</a>:</h4>
<p>I'm debugging an issue where a program compiles fine, but another version with a very minor change is rejected by the borrow checker.</p>
<p>In the renumbered MIR there is very minor and expected difference, however I don't understand why that difference makes any difference for borrow checking. Basically, in the working version I have</p>
<div class="codehilite"><pre><span></span><code>bb1:
    ...
    _6 = f(x, y) [return: bb2]

bb2:
    ...
    FakeRead(ForLet, _6);
    ...
    _10 = &amp;&#39;_#7r (*_6);
</code></pre></div>
<p>in the failing version:</p>
<div class="codehilite"><pre><span></span><code>bb1:
    ...
    _7 = f(x, y) [return: bb2]

bb2:
    ...
    _6 = &amp;&#39;_#7r (*_7);
    FakeRead(ForLet, _6);
    ...
    _11 = &amp;&#39;_#8r (*_6);
</code></pre></div>
<p>In other words, one <code>&amp;*</code> on the return value of the function works, but if I do it twice it fails.</p>
<p>I'm trying to understand why that is. Any tips on where to start? I've been staring at the borrow checker logs, but no luck so far. For some reason in the working version <code>_10</code> does not borrow from <code>x</code>, but <code>_11</code> in the failing version does. I'm trying to understand why.</p>



<a name="231066577"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231066577" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Aaron Hill <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231066577">(Mar 19 2021 at 18:10)</a>:</h4>
<p>Can you share the code?</p>



<a name="231070056"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231070056" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> osa1 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231070056">(Mar 19 2021 at 18:34)</a>:</h4>
<p><a href="http://lib.rs">lib.rs</a>:</p>
<div class="codehilite"><pre><span></span><code>pub struct A(*mut ());

unsafe impl Send for A {}

impl A {
    pub fn new() -&gt; &amp;&#39;static mut A {
        static mut a: A = A(std::ptr::null_mut());
        unsafe { &amp;mut a }
    }
}

pub struct B&lt;&#39;a&gt;(pub &amp;&#39;a mut A);

impl&lt;&#39;a&gt; std::ops::Index&lt;usize&gt; for B&lt;&#39;a&gt; {
    type Output = ();

    fn index(&amp;self, _idx: usize) -&gt; &amp;() {
        &amp;()
    }
}

pub async fn baz(_v: &amp;()) {}

pub fn assert_send&lt;T: Send&gt;(_: T) {}
</code></pre></div>
<p>Works:</p>
<div class="codehilite"><pre><span></span><code>use lib::*;
use std::ops::Index;

pub async fn bar() -&gt; () {
    let a = B(A::new());
    let r = a.index(0);
    baz(r).await;
}

pub fn test() {
    assert_send(bar())
}
</code></pre></div>
<p>Fails:</p>
<div class="codehilite"><pre><span></span><code>use lib::*;


pub async fn bar() -&gt; () {
    let a = B(A::new());
    let r = &amp;a[0];
    baz(r).await;
}

pub fn test() {
    assert_send(bar())
}
</code></pre></div>



<a name="231113599"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231113599" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231113599">(Mar 20 2021 at 02:03)</a>:</h4>
<p>I would expect that the difference between these two is not in the code that gets executed, but rather in the composition of the generator struct that the compiler generates for <code>async fn bar()</code>. Specifically, I think that <code>a</code> is in both structs (it has to be dropped after the await) but <code>r</code> or one of the temporaries is also in the struct in the failing version, which makes the struct not <code>Send</code> because <code>&amp;B</code> is not <code>Send</code>. Here's another variation on your code that works:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">bar</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="n">A</span>::<span class="n">new</span><span class="p">());</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span><span class="w"> </span><span class="n">baz</span><span class="p">(</span><span class="n">r</span><span class="p">)</span><span class="w"> </span><span class="p">}.</span><span class="k">await</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">test</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">assert_send</span><span class="p">(</span><span class="n">bar</span><span class="p">())</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>I think this is discarding whatever temporaries are involved in the <code>&amp;a[0]</code> expression so that they are not held across the await point.</p>



<a name="231113993"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231113993" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231113993">(Mar 20 2021 at 02:08)</a>:</h4>
<p>Even this causes the issue:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">B</span><span class="p">(</span><span class="n">A</span>::<span class="n">new</span><span class="p">());</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">_p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">a</span><span class="p">;</span><span class="w"> </span><span class="c1">// comment this out and it becomes Send</span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="n">baz</span><span class="p">(</span><span class="n">r</span><span class="p">).</span><span class="k">await</span><span class="p">;</span><span class="w"></span>
</code></pre></div>



<a name="231114070"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231114070" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231114070">(Mar 20 2021 at 02:10)</a>:</h4>
<p>so it looks like code-wise the reason for the difference is temporary promotion of <code>&amp;a</code> in the expression <code>index(&amp;a, 0)</code> to hoist a declaration of <code>&amp;a</code> into a let-binding that is borrowed from to create <code>r</code></p>



<a name="231114403"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231114403" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231114403">(Mar 20 2021 at 02:17)</a>:</h4>
<p>Apparently <code>drop(_p)</code> is not sufficient to get it out of the generated struct, but scoping it (as in <code>{ let _p = &amp;a; }</code>) is. I should look into what the actual rules for generating the generator struct are - this looks like something that needs a spec</p>



<a name="231137452"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Understanding%20borrow%20checking%20of%20a%20program/near/231137452" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> osa1 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Understanding.20borrow.20checking.20of.20a.20program.html#231137452">(Mar 20 2021 at 10:18)</a>:</h4>
<p>Hm, so I was thinking that the async/await stuff in this code are just a red herring and the real problem is borrows/loans kept alive for too long, but you seem to think that the problem is actually capturing.. which I think that makes sense.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>